/*LICENSE_BEGIN
 * ******************************************************************
 * All original parts of SoccerScope2003 have copyright (2003) by
 * Team YowAI, represented by Mr. Shuhei Shiota
 * The Department of Creative Informatics
 * The Graduate School of Information Science and Technology
 * The University of Tokyo
 * 
 * Additional classes (except libraries in /lib) were developed by 
 * the Dainamite Robocup-Team of the DAI-Labor, TU-Berlin 
 * (www.dai-labor.de)
 * 
 * Extended/new classes/packages are:
 *   soccerscope.analyzer.LogfileAnalyzer
 *   soccerscope.daistatistic.*
 *   soccerscope.daistatistic.charts.*
 *   soccerscope.daistatistic.tools.*
 *   soccerscope.db.*
 *   soccerscope.dialog.*
 *   soccerscope.model.PlayerWorldModel
 *   soccerscope.model.SimplePlayer
 *   soccerscope.net.AgentConnector
 *   soccerscope.training.*
 *   soccerscope.training.conditions.*
 * ******************************************************************
LICENSE_END*/
package soccerscope.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;

import soccerscope.util.GameAnalyzer;
import soccerscope.util.Time;

public class SceneSet implements Serializable {

    /**
     * id for serialization. 
     */
    private static final long serialVersionUID = 3256726186435426101L;

	private ArrayList<Scene> sceneList;

	private int[] timeTable;

	private boolean[] validTable;

	private ArrayList<GameEvent> eventList;

	private Class sceneType;
    
    /** List of start scenes of changing play modes. */
    private ScenePlayModeList playModeList;

	/**
	 * 
	 */
	public SceneSet(Class sceneType) {
        // Init the play mode list and put the first scene into it
        playModeList = new ScenePlayModeList();

        this.sceneType = sceneType;
		this.sceneList = new ArrayList<Scene>(Time.GAME_TIME);
		this.timeTable = new int[Time.MAX_TIME + 1];
		this.validTable = new boolean[Time.MAX_TIME + 1];
		for (int i = 0; i < Time.MAX_TIME + 1; i++)
			this.validTable[i] = false;

		if (this.sceneType == ClientScene.class) {
			addScene(ClientScene.createScene());
		}
		this.eventList = new ArrayList<GameEvent>();
        
	}

	/**
	 * 
	 * 
	 * @return
	 */
	public int getLimitTime() {
		return ((ClientScene) this.sceneList.get(this.sceneList.size() - 1)).time;
	}

	/**
	 * 
	 * @param scene
	 * @return
	 */
	public boolean addScene(Scene scene) {
		if (Time.isValid(scene.time)) {
			if (!this.validTable[scene.time]) {
				this.timeTable[scene.time] = this.sceneList.size();
				this.validTable[scene.time] = true;
			}
			this.sceneList.add(scene);
            playModeList.addSceneMode(sceneList.size() - 1, scene.time, scene.pmode);
			return true;
		}
		return false;
	}

	/**
	 * 
	 * @return
	 */
	public ClientScene firstScene() {
		return (ClientScene) this.sceneList.get(0);
	}

	/**
	 * 
	 * @return
	 */
	public ClientScene lastScene() {
		return (ClientScene) this.sceneList.get(this.sceneList.size() - 1);
	}

	/**
	 * 
	 * @param index
	 * @return
	 */
	public ClientScene elementAt(int index) {
		return (ClientScene) this.sceneList.get(index);
	}

	/**
	 * 
	 * @param clientScene
	 * @param time
	 */
	public void setScene(ClientScene clientScene, int time) {
		this.validTable[time] = true;
		this.sceneList.set(this.timeTable[time], clientScene);
	}

	/**
	 * 
	 * @param time
	 * @return Scene
	 */
	public Scene getScene(int time) {
		return this.sceneList.get(this.timeTable[time]);
	}

	/**
	 * 
	 * @param time
	 * @return
	 */
	public boolean hasScene(int time) {
		if (Time.isValid(time))
			return this.validTable[time];
		return false;
	}

	/**
	 * 
	 * @param time
	 * @return
	 */
	public int getIndex(int time) {
		return this.timeTable[time];
	}

	/**
	 * 
	 * @param clientScene
	 * @return
	 */
	public int indexOf(ClientScene clientScene) {
		return this.sceneList.indexOf(clientScene);
	}

	/**
	 * 
	 * @return
	 */
	public int size() {
		return this.sceneList.size();
	}

	/**
	 * 
	 */
	public void clear() {
		this.sceneList.clear();
		this.timeTable = new int[Time.MAX_TIME + 1];
		this.validTable = new boolean[Time.MAX_TIME + 1];
		for (int i = 0; i < Time.MAX_TIME + 1; i++)
			this.validTable[i] = false;
		addScene(ClientScene.createScene());
		this.eventList.clear();
	}

	/**
	 * 
	 * @return Iterator
	 */
	public Iterator iterator() {
		return this.sceneList.iterator();
	}

	/**
	 * 
	 */
	public void analyze() {
		this.eventList.clear();
		this.eventList = GameAnalyzer.analyze(this);
		Collections.sort(this.eventList);
	}

	/**
	 * 
	 * @param time
	 * @return
	 */
	public GameEvent getNextEvent(int time) {
		Iterator it = this.eventList.iterator();
		GameEvent ge;
		while (it.hasNext()) {
			ge = (GameEvent) it.next();
			if (ge.time > time)
				return ge;
		}
		return null;
	}

	/**
	 * 
	 * @param time
	 * @return
	 */
	public GameEvent getPrevEvent(int time) {
		int size = this.eventList.size();
		GameEvent ge;
		for (int i = size - 1; i >= 0; i--) {
			ge = (GameEvent) this.eventList.get(i);
			if (ge.time < time)
				return ge;
		}
		return null;
	}

	/**
	 * This methd adds a new Training-Scene. Because these scenes occurs only
	 * single-wise, all other scenes are deleted (only when loading a scene).
	 * 
	 * @param scene -
	 *            the new scene
	 */
	public void addTrainingScene(ClientScene scene) {
		this.addScene(scene);
		for (int i = 0; i < this.sceneList.size() - 1; i++)
			this.sceneList.remove(0);

	}
    
    /**
     * Returns the list of scenes where the play mode has changed.
     * @return the list of scenes where the play mode has changed
     */
    public ScenePlayModeList getScenePlayModeList() {
        return playModeList;
    }
    
    /**
     * calculates the newest scene of the given cycle number.
     * @param cycleNumber the cycle number
     * @return the last scene with this cycle number or null if the scene does not exists
     */
    public ClientScene getSceneOfCycle(int cycleNumber) {
        if (hasScene(cycleNumber)) {
            int num = getIndex(cycleNumber);
            while (sceneList.size() > num && getScene(num + 1).time == cycleNumber) {
                num++;
            }
            return (ClientScene) sceneList.get(num);
        }
        return null;

    }
}

/*
 * $Log: SceneSet.java,v $
 * Revision 1.1.28.5  2006/11/23 09:41:02  endert
 * Added License Note at top of each *.java file.
 *
 * Revision 1.1.28.4  2006/11/13 16:50:18  endert
 * Removed CVS-Logs and author tags
 *
 * Revision 1.1.28.3  2006/10/25 14:33:34  endert
 * Latest SoccerScope Version plus Database ability
 *
 * Revision 1.1.14.4  2006/08/04 14:00:17  benjaboe
 * PlayerData will be put in the correct cycle not in the last scene
 *
 * Revision 1.1.14.3  2006/07/29 13:32:42  benjaboe
 * Some parts of the AgentModelLayer can be activated/deactivated.
 * The drawing does not use the LocalScene any more - LocalScene is deleted.
 *
 * Revision 1.1.14.2  2006/07/24 16:24:47  benjaboe
 * Jump to scenes is possible
 *
 * Revision 1.1.14.1  2006/07/08 07:40:02  benjaboe
 * Speichern und Laden scheint zu funktionieren
 *
 * Revision 1.1  2006/03/13 07:37:44  axle
 * moved from ROOT/src for Maven 2 Buildsystem and Team/Soccerscope separation
 *
 * Revision 1.6  2006/03/07 12:46:01  endert
 * Merge after refactoring:
 *  - New State-Interface: One Method for each action type
 *  - Action Bean removed - ActionFactorys for helper methods, States calculate
 *    main-Action themselves
 *  - formatted code
 *  - added State-List in Monitor (Context-Menu of Player)
 *  - other smaller stuff
 *
 * Revision 1.5.2.1  2006/02/25 22:07:24  wetzker
 * formated
 *
 * Revision 1.5  2006/02/24 18:53:56  wetzker
 * used enums for Play_modes and Referee_messages
 * - still has to be improved after creation of new Play_mode-Model
 * - tagged old version
 * removed millions of warnings
 *
 * Revision 1.4  2006/02/22 16:04:43  endert
 * This is done:
 * - Rebound SoccerScope to Agents (can be added or removed in config-file)
 * - Situations now all extend abstract class Situation
 * - Refactorings: ActionBean _ removed from Attributes
 * - SoccerScope will automatically connect to host given in Start-Call
 * - Trainer uses the same host as soccerscope
 * - Removed unused stuff (old confs, bat, etc.)
 * - Code formatted (good luck when merging)
 * - organized imports
 * - all that i forgot to mention here
 * Revision 1.3 2005/10/25 20:51:37 endert Added Training-Editor to
 * SoccerScope, restructuring in some old classes and some experimental stuff
 * (goals, commitments, mental model)
 * 
 * Revision 1.2.4.1 2005/10/11 18:29:52 endert TrainingModel moved to WorldModel
 * (of SoccerScope)
 * 
 * Revision 1.2 2005/10/01 13:39:15 wetzker organized imports
 * 
 * Revision 1.1 2005/04/20 10:39:03 endert Fresh Team Repository installation
 * from /home/e/endert/Robocup to here.
 * 
 * Revision 1.4 2005/03/13 14:47:26 haeder * some modifications to reduce the
 * number of warnings ;-) - removed unreadable comments
 * 
 * Revision 1.3 2005/02/06 07:17:27 maketi Added soccerscope with connection to
 * our world model
 * 
 * Revision 1.8 2003/06/09 09:00:34 newone jump��5
 * 
 * Revision 1.7 2002/09/17 07:46:19 koji
 * WatchBall��ZoomBall�Υ��������ѹ���Publish�ѤΥѥͥ��ɲá�������ν���
 * �Υ�����򥫥���Ȥ��Ƥ��ʤ��ä��Τ�5
 * 
 * Revision 1.6 2002/09/12 11:25:37 koji
 * ��ײ��ϡ�����ǽ���ɲá������ե�����졼�����ե������б�
 * 
 * Revision 1.5 2002/09/09 09:56:35 koji
 * Preference��GUI��.,soccerscope.conf��Ƴ��
 * 
 * Revision 1.4 2002/09/06 10:05:50 koji Preference��GUI��d�äȺ�.
 * 
 * Revision 1.3 2002/09/05 09:46:33 koji
 * ���٥�ȥ����u�ǽ���ɲ�
 * 
 * Revision 1.2 2002/08/30 10:47:31 koji bmpviewer����Jimi�б�
 * 
 * Revision 1.1.1.1 2002/03/01 14:12:54 koji CVS�����
 * 
 */
